package com.media.module.widget;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;

import com.droid.data.utils.Datautils;
import com.media.module.interfaces.AudioStater;
import com.media.module.interfaces.MediaRecordFuncStater;
import com.media.module.model.OutputFormatMode;
import com.media.module.utils.AudioRecordFunc;
import com.media.module.utils.AudioUtils;
import com.media.module.utils.CameraUtils;
import com.media.module.utils.MediaRecordFunc;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.media.AudioRecord;
import android.os.Environment;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Toast;

/**
 * WaveformView.
 *
 * @author zhyc
 * @since 14/9/24.
 */
public class WaveformView extends View implements MediaRecordFuncStater {
	private Context mContext;
	private static final float MIN_AMPLITUDE = 0.0575f;
	private float mPrimaryWidth = 2.0f;
	private float mSecondaryWidth = 1.0f;
	private float mAmplitude = MIN_AMPLITUDE;
	private int mWaveColor = Color.argb(255, 0, 255, 234);
	private int mDensity = 2;
	private int mWaveCount = 5;
	private float mFrequency = 0.1875f;
	private float mPhaseShift = -0.1875f;
	private float mPhase = mPhaseShift;

	private Paint mPrimaryPaint;
	private Paint mSecondaryPaint;

	private Path mPath;

	private float mLastX;
	private float mLastY;

	private MediaRecordFunc mMediaRecordFunc;
	private AudioRecordFunc mAudioRecordFunc;
	private AudioStater mAudioStater;
	private boolean isRecording = false;
	private boolean misStart = false;

	private String mstrSaveAudioDirPath;
	// 预缓存地址一
	private String mstrCurrentAudioFilePath = "";
	private String mstrSaveAudioFilePath = "";
	private ArrayList<String> marrAudioPath;

	private OutputFormatMode mFormatMode;

	private int BASE = 1;

	public WaveformView(Context context) {
		this(context, null);
		initialize();
	}

	public WaveformView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
		initialize();
	}

	public WaveformView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mContext = context;
		initialize();
	}

	public void setAudioStater(AudioStater audioStater) {
		this.mAudioStater = audioStater;
	}

	private void initialize() {
		mPrimaryPaint = new Paint();
		mPrimaryPaint.setStrokeWidth(mPrimaryWidth);
		mPrimaryPaint.setAntiAlias(true);
		mPrimaryPaint.setStyle(Paint.Style.STROKE);
		mPrimaryPaint.setColor(mWaveColor);

		mSecondaryPaint = new Paint();
		mSecondaryPaint.setStrokeWidth(mSecondaryWidth);
		mSecondaryPaint.setAntiAlias(true);
		mSecondaryPaint.setStyle(Paint.Style.STROKE);
		mSecondaryPaint.setColor(mWaveColor);

		mPath = new Path();
	}

	public void updateAmplitude(float amplitude) {
		mAmplitude = Math.max(amplitude, MIN_AMPLITUDE);
	}

	@Override
	protected void onDraw(Canvas canvas) {

		int width = getWidth();
		int height = getHeight();

		for (int l = 0; l < mWaveCount; ++l) {
			float midH = height / 2.0f;
			float midW = width / 2.0f;

			float maxAmplitude = midH / 2f - 4.0f;
			float progress = 1.0f - l * 1.0f / mWaveCount;
			float normalAmplitude = (1.5f * progress - 0.5f) * mAmplitude;

			float multiplier = (float) Math.min(1.0, (progress / 3.0f * 2.0f) + (1.0f / 3.0f));

			if (l != 0) {
				mSecondaryPaint.setAlpha((int) (multiplier * 255));
			}

			mPath.reset();
			for (int x = 0; x < width + mDensity; x += mDensity) {
				float scaling = 1f - (float) Math.pow(1 / midW * (x - midW), 2);
				float y = scaling * maxAmplitude * normalAmplitude
						* (float) Math.sin(180 * x * mFrequency / (width * Math.PI) + mPhase) + midH;
				if (!misStart) {
					y = midH;
				}
				if (x == 0) {
					mPath.moveTo(x, y);
				} else {
					mPath.lineTo(x, y);
				}

				mLastX = x;
				mLastY = y;
			}

			if (l == 0) {
				canvas.drawPath(mPath, mPrimaryPaint);
			} else {
				canvas.drawPath(mPath, mSecondaryPaint);
			}
		}

		mPhase += mPhaseShift;
		invalidate();
	}

	public static String getSDPath(Context context, String pathName) {
		File sdDir = null;
		boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); // 判断sd卡是否存在
		if (sdCardExist) {
			sdDir = Environment.getExternalStorageDirectory();
		} else if (!sdCardExist) {

			Toast.makeText(context, "SD卡不存在", Toast.LENGTH_SHORT).show();

		}
		File eis = new File(sdDir.toString() + "/" + pathName + "/");
		try {
			if (!eis.exists()) {
				eis.mkdir();
			}
		} catch (Exception e) {

		}
		return sdDir.toString() + "/" + pathName + "/";

	}

	@Override
	public void onMediaRecordFuncStart(long time) {
		mAudioStater.onAudioStart(time);

	}

	@Override
	public void onMediaRecordFuncStop(long time) {
		mAudioStater.onAudioStop(time);

	}

	/**
	 * 录音唤醒
	 */
	public boolean onResumeRecording(boolean isStart) {
		return startRecording(mstrSaveAudioDirPath, mFormatMode, isStart);
	}

	/**
	 * 开始录音
	 */
	public boolean startRecording(String dirPath, OutputFormatMode formatMode, boolean isStart) {
		if (marrAudioPath == null) {
			marrAudioPath = new ArrayList<String>();
		}
		if (isStart) {
			marrAudioPath.clear();
			mstrSaveAudioFilePath = "";
		}
		mFormatMode = formatMode;
		mstrSaveAudioDirPath = dirPath;
		mstrCurrentAudioFilePath = mstrSaveAudioDirPath + getAudioFileName();
		// 如果正在录音，则返回
		if (isRecording) {
			return isRecording;
		}
		// 初始化
		initRecorder();

		if (mMediaRecordFunc != null) {
			mMediaRecordFunc.startRecordAndFile(mstrCurrentAudioFilePath);
		} else {
			mAudioRecordFunc.startRecordAndFile(mstrCurrentAudioFilePath, isStart);
		}
		startWave();
		new Thread(new AudioRecordThread()).start();
		isRecording = true;
		return isRecording;
	}

	/**
	 * 停止录音，并且转换文件,<br/>
	 * <b>这很可能是个耗时操作，建议在后台中做
	 * 
	 * @return
	 */
	public boolean stopRecordingAndConvertFile(boolean isPause) {
		if (!isRecording) {
			return isRecording;
		}
		stop();
		isRecording = false;
		if (isPause) {
			if(mstrCurrentAudioFilePath != null && !mstrCurrentAudioFilePath.isEmpty()){
				marrAudioPath.add(mstrCurrentAudioFilePath);
			}
		} else {
			String lstrFilePath = mstrSaveAudioDirPath + getAudioFileName();
			if (mAudioRecordFunc != null) {
				try {
					Thread.sleep(500);
				} catch (Exception e) {
					e.printStackTrace();
				}
				mAudioRecordFunc.copyWaveFile(mAudioRecordFunc.getmAudioName(), lstrFilePath);
				mstrSaveAudioFilePath = lstrFilePath;
				return isRecording;
			}
			if(mstrCurrentAudioFilePath != null && !mstrCurrentAudioFilePath.isEmpty()){
				marrAudioPath.add(mstrCurrentAudioFilePath);
			}
			String[] strAudioPath = marrAudioPath.toArray(new String[0]);
			try {
				AudioUtils.merge(strAudioPath, lstrFilePath);
				mstrSaveAudioFilePath = lstrFilePath;
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				for (int i = 0; i < marrAudioPath.size() ; i++) {
					File tempFile = new File(marrAudioPath.get(i));
					if (tempFile.exists()) {
						tempFile.delete();
					}
				}
				marrAudioPath.clear();
			}
		}
		return isRecording;// convertOk==true,return true
	}

	/**
	 * 获取文件名
	 * 
	 * @return
	 */
	private String getAudioFileName() {
		return "AUDIO_" + CameraUtils.getModifyTime() + mFormatMode.toString();
	}

	public String getFilePath() {
		return mstrSaveAudioFilePath;
	}

	/**
	 * 清理文件
	 * 
	 * @param cleanFlag
	 *            RAW,MP3 or RAW|MP3
	 */
	public void cleanFile() {
		try {
			File f = null;
			f = new File(mstrSaveAudioDirPath);
			if (f.exists()) {
				f.delete();
			}
			f = null;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 初始化
	 */
	private void initRecorder() {
		if (mFormatMode == OutputFormatMode.AMR) {
			mMediaRecordFunc = MediaRecordFunc.getInstance();
			mMediaRecordFunc.setMediaRecordFuncStater(this);
			mAudioRecordFunc = null;
			return;
		}
		if (mFormatMode == OutputFormatMode.WAV) {
			mAudioRecordFunc = AudioRecordFunc.getInstance();
			mAudioRecordFunc.setMediaRecordFuncStater(this);
			mMediaRecordFunc = null;
		}
	}

	class AudioRecordThread implements Runnable {

		@Override
		public void run() {
			startBufferedWrite();// 往文件中写入裸数据
		}
	}
	
	/**
	 * 更新音量（分贝）
	 * 
	 * @param recorder
	 */
	private void startBufferedWrite() {
		// new一个byte数组用来存一些字节数据，大小为缓冲区大小
		if (mAudioRecordFunc != null) {
			int size = mAudioRecordFunc.getBufferSizeInBytes();
			short[] buffer = new short[size];
			File file = null;
			RandomAccessFile randomAccessFile = null;
			try {
				file = new File(mAudioRecordFunc.getmAudioName());
				randomAccessFile = new RandomAccessFile(file, "rw");
				while (isRecording) {
					// 平方和除以数据总长度，得到音量大小。
					// double mean = recorder.getMaxAmplitude() / (double) BASE;
					// double volume = 10 * Math.log10(mean);
					// int pitch = volume > 0 ? (int) volume : 1;
					int pitchInHz = 0;
					double mean = 0;
					double volume = 0;
					int r = mAudioRecordFunc.getAudioRecord().read(buffer, 0, size);
					long v = 0;
					if (AudioRecord.ERROR_INVALID_OPERATION != r && randomAccessFile != null) {
						try {
							randomAccessFile.seek(randomAccessFile.length());
							for (int i = 0; i < buffer.length; i++) {
								byte[] data = Datautils.shortToByteArray(buffer[i]);
								randomAccessFile.write(data, 0, data.length);
								// 将 buffer 内容取出，进行平方和运算
								v += buffer[i] * buffer[i];
							}
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
					mean = (int) (v / (double) r);
					if (mean > 0) {
						volume = 10 * Math.log10(mean);
					}
					pitchInHz = volume > 0 ? (int) volume : 1;
					updateAmplitude(pitchInHz * 0.1f / 6);
				}
			} catch (Exception e) {
				e.fillInStackTrace();
			} finally {
				if (randomAccessFile != null) {
					try {
						randomAccessFile.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		} else {
			try {
				while (isRecording) {
					int pitchInHz = 0;
					double mean = 0;
					double volume = 0;
					mean = mMediaRecordFunc.getmMediaRecorder().getMaxAmplitude() / (double) BASE;
					if (mean > 0) {
						volume = 10 * Math.log10(mean);
					}
					pitchInHz = volume > 0 ? (int) volume : 1;
					updateAmplitude(pitchInHz * 0.1f / 6);
					Thread.sleep(100);
				}
			} catch (Exception e) {
				e.fillInStackTrace();
			}
		}
	}
	
	public void stopWave() {
		misStart = false;
	}

	public void startWave() {
		misStart = true;
	}
	
	/**
	 * 取消录音
	 */
	public void stop(){
		stopWave();
		// 停止
		if (mMediaRecordFunc != null) {
			mMediaRecordFunc.stopRecordAndFile();
		} else if(mAudioRecordFunc != null) {
			mAudioRecordFunc.stopRecordAndFile();
		}
	}
}
